﻿using System;
using System.Collections.Generic;
using System.Data.SqlClient;

namespace Evpo.ContactData.Data
{
    public abstract class AdapterBase
    {
        internal AdapterBase(Connection connection)
        {
            _conn = connection;
        }

        #region Fields
        protected readonly Connection _conn;
        #endregion

        #region Properties
        protected abstract string PrimaryKeyField
        {
            get;
        }

        protected abstract string SProcToDelete
        {
            get;
        }

        protected abstract string SProcToSave
        {
            get;
        }

        protected abstract string SProcToLoad
        {
            get;
        }

        protected abstract string SProcToQuery
        {
            get;
        }
        #endregion

        #region Methods

        protected void FillFromQuery<T>(List<SqlParameter> parameters, List<T> results) where T : DataObject, new()
        {
            FillFromQuery<T>(parameters, results, SProcToQuery);
        }

        protected void FillFromQuery<T>(List<SqlParameter> parameters, List<T> results, string sprocToQuery) where T : DataObject, new()
        {
            if (parameters == null)
                throw new ArgumentNullException("parameters");
            if (results == null)
                throw new ArgumentNullException("results");

            using (var procReader = new ProcedureOutputReader(_conn, sprocToQuery, parameters))
            {
                SqlDataReader sqlReader = procReader.CreateReader();
                while (sqlReader.Read())
                {
                    T dataObject = new T();
                    dataObject.FillFieldsFromReader(procReader);
                    results.Add(dataObject);
                }
            }
        }

        protected T Load<T>(int id) where T : DataObject, new()
        {
            T retVal = null;
            using (var procReader = new ProcedureOutputReader(_conn, SProcToLoad,
                new List<SqlParameter>() { new SqlParameter("@" + PrimaryKeyField, id), }))
            {
                SqlDataReader reader = procReader.CreateReader();
                reader.Read();
                retVal = new T();
                retVal.FillFieldsFromReader(procReader);
            }
            return retVal;
        }

        protected void Save<T>(T dataObject, bool isNew) where T : DataObject
        {
            var idParam = new SqlParameter("@" + PrimaryKeyField, System.Data.SqlDbType.Int)
            {
                Direction = System.Data.ParameterDirection.InputOutput
            };

            List<SqlParameter> parameters = new List<SqlParameter>();
            dataObject.FillParametersToSave(parameters);
            parameters.Add(idParam);

            foreach (SqlParameter parameter in parameters)
            {
                if (parameter.Value == null)
                    parameter.Value = DBNull.Value;
            }

            if (!isNew)
                idParam.Value = dataObject.PrimaryKeyValue;

            using (var execProvider = new StatementExecutionProvider(_conn, SProcToSave, parameters))
            {
                execProvider.ExecuteNonQuery();
            }

            if (isNew)
                dataObject.PrimaryKeyValue = (int)idParam.Value;
        }

        public void Delete(int id)
        {
            var parameters = new List<SqlParameter>()
            {
                new SqlParameter("@"+PrimaryKeyField, id),
            };

            using (var execProvider =
                new StatementExecutionProvider(_conn, SProcToDelete, parameters))
            {
                execProvider.ExecuteNonQuery();
            }
        }
        #endregion Methods
    }
}
